﻿using System;
using System.Collections.Specialized;
using System.IO;
using System.Web.UI;
using Intellego.Web.ValidationEngine;
using MIAPWEB.Common;

namespace MIAPWEB.Forms
{
    /// <summary>
    /// Clase base de las paginas contenidas en la página maestra de la aplicación.
    /// </summary>
    public class PageBase : Page
    {
        #region Constantes

        /// <summary>
        /// Cadena de acceso al objeto 'ValidationEngine' del View-State.
        /// </summary>
        private const string ValidationEngineSessionString = "validationengine";

        /// <summary>
        /// Cadena de acceso al objeto 'ApplyViewStateCompression' del View-State.
        /// </summary>
        private const string CompressionEnabledViewStateString = "applyviewstatecompression";

        #endregion

        #region Fields

        /// <summary>
        /// Componente para validaciones del lado del cliente.
        /// </summary>
        private ValidationEngine validationEngine;

        #endregion

        #region Properties

        /// <summary>
        /// Obtiene la página maestra asociada a la página actual.
        /// </summary>
        public Main CurrentMasterPage
        {
            get
            {
                return (Main)Master;
            }
        }

        /// <summary>
        /// Obtiene el componente para validaciones del lado del cliente de la página actual.
        /// </summary>
        public ValidationEngine ValidationEngine
        {
            get
            {
                return this.validationEngine ?? (this.validationEngine = new ValidationEngine(this));
            }
        }

        /// <summary>
        /// Obtiene o establece un valor el cual indica si se comprime el <see cref="Control.ViewState"/> de la página actual
        /// </summary>
        public bool ApplyViewStateCompression
        {
            get
            {
                return this.ViewState[CompressionEnabledViewStateString] != null && (bool)this.ViewState[CompressionEnabledViewStateString];
            }

            set
            {
                this.ViewState[CompressionEnabledViewStateString] = value;
            }
        }

        /// <summary>
        /// Obtiene o establece la pagina previa.
        /// </summary>
        public new string PreviousPage
        {
            get
            {
                if (this.ViewState["previouspage"] == null)
                {
                    if (string.IsNullOrEmpty(this.Request.QueryString[@"previousPage"]))
                    {
                        this.ViewState["previouspage"] = AppUrls.Default;
                    }
                    else
                    {
                        this.ViewState["previouspage"] = this.Request.QueryString[@"previousPage"].Replace("||", "&");
                    }
                }

                return this.ViewState["previouspage"].ToString();
            }

            set
            {
                this.ViewState["previouspage"] = value;
            }
        }

        #endregion

        #region Events

        /// <summary>
        /// Carga la información del <see cref="Control.ViewState"/> de la página actual.
        /// </summary>
        /// <returns>El estado de vista guardado.</returns>
        protected override object LoadPageStateFromPersistenceMedium()
        {
            if (this.ApplyViewStateCompression)
            {
                // Ejecutar la compresión del View-State de la página.
                CompressionHelper compressionHelper = new CompressionHelper();
                LosFormatter losFormatter = new LosFormatter();

                this.PageStatePersister.Load();
                string alteredViewState = this.PageStatePersister.ViewState.ToString();

                byte[] alteredViewStateBytes = Convert.FromBase64String(alteredViewState);
                alteredViewStateBytes = compressionHelper.Decompress(alteredViewStateBytes);

                object rawViewState = losFormatter.Deserialize(Convert.ToBase64String(alteredViewStateBytes));
                return new Pair(this.PageStatePersister.ControlState, rawViewState);
            }

            return base.LoadPageStateFromPersistenceMedium();
        }

        /// <summary>
        /// Guarda información del <see cref="Control.ViewState"/> de la página actual.
        /// </summary>
        /// <param name="viewState">Objeto en el que se almacenara la información del estado de vista.</param>
        protected override void SavePageStateToPersistenceMedium(object viewState)
        {
            if (this.ApplyViewStateCompression)
            {
                // Ejecutar la descompresión del View-State de la página.
                CompressionHelper compressionHelper = new CompressionHelper();
                LosFormatter losFormatter = new LosFormatter();
                StringWriter stringWriter = new StringWriter();
                object rawViewState;

                if (viewState is Pair)
                {
                    Pair rawPair = (Pair)viewState;
                    this.PageStatePersister.ControlState = rawPair.First;
                    rawViewState = rawPair.Second;
                }
                else
                {
                    rawViewState = viewState;
                }

                losFormatter.Serialize(stringWriter, rawViewState);
                string rawViewStateString = stringWriter.ToString();

                byte[] viewStateBytes = Convert.FromBase64String(rawViewStateString);
                viewStateBytes = compressionHelper.Compress(viewStateBytes);

                string alteredViewState = Convert.ToBase64String(viewStateBytes);

                this.PageStatePersister.ViewState = alteredViewState;
                this.PageStatePersister.Save();
            }
            else
            {
                base.SavePageStateToPersistenceMedium(viewState);
            }
        }

        /// <summary>
        /// Provoca el evento de PreInit al principio de la inicialización de la página.
        /// </summary>
        /// <param name="e">Objeto EventArgs que contiene los datos del evento.</param>
        protected override void OnPreInit(EventArgs e)
        {
            if (!AppSessionManager.Instance.EstaAutenticado)
            {
                Response.Redirect(AppUrls.SessionTimeOut);
            }
            base.OnPreInit(e);

            if (!this.IsPostBack)
            {
                // Comprobar que el usuario de la sesión cuenta con los permisos suficientes para accesar a la página.
                if (!AppSessionManager.Instance.HasSessionUserAccessPermission(Request.UrlReferrer, Request.Url))
                {
                    Response.Redirect(AppUrls.ErrorPermisos);
                }
            }
        }

        /// <summary>
        /// Evento que se genera antes de que se envie el contenido de la pagina al cliente
        /// </summary>
        /// <param name="e">Objeto EventArgs que contiene los datos del evento.</param>
        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);

            if (this.validationEngine != null)
            {
                this.Page.ClientScript.RegisterStartupScript(this.Page.GetType(), "ValidationEngine", this.validationEngine.GenerateScript(), true);
            }
        }
        #endregion

        #region Methods

        /// <summary>
        /// Muestra un mensaje emergente al usuario.
        /// </summary>
        /// <param name="message">Mensaje a mostrar.</param>
        public void ShowMessage(string message)
        {
            this.CurrentMasterPage.ShowMessage(message);
        }

        /// <summary>
        /// Muestra un mensaje emergente al usuario.
        /// </summary>
        /// <param name="message">Mensaje a mostrar.</param>
        /// <param name="urlReridect">URL al que te va a redirecciónar</param>
        public void ShowMessage(string message, string urlReridect)
        {
            this.CurrentMasterPage.ShowMessage(message, urlReridect);
        }

        /// <summary>
        /// Redirecciona a la página previa.
        /// </summary>
        /// <param name="conParametos">Especifica si el QueryString de la página actual sera enviado a la página previa.</param>
        public void SavePreviousPage(bool conParametos)
        {
            var referrer = string.Empty;
            if (!conParametos)
            {
                if (this.Request.UrlReferrer != null)
                {
                    referrer = this.Request.UrlReferrer.ToString();
                }
            }
            else
            {
                if (!string.IsNullOrEmpty(this.Request.Url.ToString()))
                {
                    var urlReferrer = this.Request.UrlReferrer;
                    if (urlReferrer != null)
                    {
                        referrer = this.Request.Url.ToString().Replace(this.Request.Url.AbsolutePath, urlReferrer.AbsolutePath);
                    }
                }
            }

            if (!string.IsNullOrEmpty(referrer))
            {
                var urlReferrer = referrer;
                if (string.IsNullOrEmpty(Request.QueryString[@"backNavitagion"]))
                {
                    this.PreviousPage = urlReferrer;
                }
            }
            else
            {
                this.PreviousPage = AppUrls.Default;
            }
        }

        /// <summary>
        /// Recupera PreviousPage del QueryString registrado
        /// </summary>
        public string GetPreviousPageQueryString
        {
            get
            {
                return string.Format("{0}={1}", @"previousPage", this.PreviousPage.Replace("&", "||"));
            }
        }

        /// <summary>
        /// Metodo que regresa a la pagina anterior
        /// </summary>
        public void ReturnToPreviousPage()
        {
            NameValueCollection valueCollection = System.Web.HttpUtility.ParseQueryString(this.PreviousPage);
            string urlNavigation = this.PreviousPage;

            if (!string.IsNullOrEmpty(valueCollection[@"previousPage"]))
            {
                if (urlNavigation.IndexOf("?", System.StringComparison.InvariantCulture) > -1)
                {
                    urlNavigation += string.Format("&{0}=1", @"backNavitagion");
                }
                else
                {
                    urlNavigation += string.Format("?{0}=1", @"backNavitagion");
                }
            }

            Response.Redirect(urlNavigation);
        }

        /// <summary>
        /// Modifica el valor de una llave
        /// </summary>
        /// <param name="key">Llave a modificar</param>
        /// <param name="newValue">Valor nuevo</param>
        /// <param name="oldValue">Valor anterior</param>
        public void EditKeyPreviousPage(string key, string newValue, string oldValue)
        {
            string pp = this.PreviousPage.Replace(string.Format("{0}={1}", key, oldValue), string.Format("{0}={1}", key, newValue));
            this.PreviousPage = pp;
        }

        /// <summary>
        /// Metodo que carga el evento click al control
        /// </summary>
        /// <param name="control">Control de tipo LinkButton</param>
        /// <param name="mensaje">Mensaje que se mostrara al usuario</param>
        public void AddConfirmDialog(System.Web.UI.WebControls.LinkButton control, string mensaje)
        {
            control.OnClientClick = string.Format("ShowMessageConfirm(this,'{0}'); return false;", mensaje);
        }

        /// <summary>
        /// Metodo que carga el evento click al control
        /// </summary>
        /// <param name="control">Control de tipo Button</param>
        /// <param name="mensaje">Mensaje que se mostrara al usuario</param>
        public void AddConfirmDialog(System.Web.UI.WebControls.Button control, string mensaje)
        {
            control.OnClientClick = string.Format("ShowMessageConfirm(this,'{0}'); return false;", mensaje);
        }
        #endregion
    }
}